#pragma once
#include "../variant.h"
#include <armadillo>

#ifdef GRAPHENETOOLS_EXPORTS
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllexport)
#endif
#else
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllimport)
#endif
#endif

class GRAPHENETOOLS_DLL_API Generator
{
	std::vector<arma::ivec4> atomsvec;
	std::vector<arma::ivec4> pvec;
	
	enum stackingtype {
		singlelayer,
		gongal
	} stacking;
	
	enum paddingtype {
		automatic,
		none,
		userdefined
	} padding;
	long userpadding;
	bool randomholes;
	double randomradius;
	long recursiveedgeetch;
	
	static const string stackingsymbol;
	static const string singlelayersymbol;
	static const string gongalsymbol;
	static const string paddingsymbol;
	static const string randomholecenterradiusssymbol;
	static const string recursiveedgeetchssymbol;

public:
	static const string inftriangulargalsymbol;
	static const string inftriangulargalrectanglesymbol;
	static const string triangulargalrectanglesymbol;

	Generator(const symbol &str, const variant &param, const rule::list &opts = rule::list());
	
	const std::vector<arma::ivec4> & atoms();
	const std::vector<arma::ivec4> & periodicity();

protected:
	static std::vector<arma::ivec4> inftriangulargal_atoms(size_t L, double R, const stackingtype &st);
	static std::vector<arma::ivec4> inftriangulargal_periodicity(size_t L, double R, const stackingtype &st);
		
	static std::vector<arma::ivec4> singletriangulargalrectangle_atoms(size_t L, double R, const stackingtype &st, arma::uvec padd = arma::uvec("0 0 0 0"));
	static std::vector<arma::ivec4> singletriangulargalrectangle_periodicity(size_t L, double R, const stackingtype &st);
	static std::vector<arma::ivec4> triangulargalrectangle_atoms(size_t L, double R, size_t Nx, size_t Ny, const stackingtype &st);
	static std::vector<arma::ivec4> triangulargalrectangle_atoms(size_t L, double R, size_t Nx, size_t Ny, const stackingtype &st, size_t padd);
	
	static std::vector<arma::ivec4> inftriangulargalrectangle_atoms(size_t L, double R, size_t Nx, size_t Ny, const stackingtype &st);
	static std::vector<arma::ivec4> inftriangulargalrectangle_periodicity(size_t L, double R, size_t Nx, size_t Ny, const stackingtype &st);
	
	static std::vector<arma::ivec4> singletriangulargalrectangle_atoms_noholes(size_t L, const stackingtype &st, arma::uvec padd = arma::uvec("0 0 0 0"));
	static std::vector<arma::ivec4> inftriangulargalrectangle_atoms_randomholes(size_t L, double R, size_t Nx, size_t Ny, const stackingtype &st, double randrad);
	
	static void recursive_edge_etching(std::vector<arma::ivec4> &unfilteredatomlist, const std::vector<arma::ivec4> & periodicity, long etchstepstogo);
};

